from django.shortcuts import render
from django.contrib.admin.views.decorators import staff_member_required
from django.views.generic import View
from django.views.decorators.http import require_POST,require_GET
from apps.news.models import NewsCategory,News,Banner
from utils import restful
from .forms import EditNewsCategoryForm,WriteNewsForm,AddBannerForm,EditNewsForm
from django.conf import settings
import os
import qiniu
from apps.news.serializers import BannerSerializer
from django.core.paginator import Paginator
import re
from django.db.models import Q
from datetime import datetime
from django.utils.timezone import make_aware
from urllib import parse
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import permission_required


@staff_member_required(login_url='index')
def index(request):
    return render(request,'cms/index.html')


@method_decorator(permission_required(perm='news.change_news',login_url='/'), name='dispatch')
class NewsListView(View):

    item_limit_per_page = 2

    def query(self,date_range,title,category):
        if date_range == '':
            start_date = datetime(2018,1,1)
            end_date = datetime.today()
        else:
            regex = r'\d{4}/\d{2}/\d{2}'
            start_date,end_date = re.findall(regex,date_range)
            start_date = datetime.strptime(start_date,'%Y/%m/%d')
            end_date = datetime.strptime(end_date, '%Y/%m/%d')

        start_date = make_aware(start_date)
        end_date = make_aware(end_date)

        if title != '':
            if category == 0:
                all_news = (
                    News.objects.select_related('category', 'author')
                        .filter(Q(pub_time__range=(start_date, end_date)) & Q(title__icontains=title))
                )
            else:
                all_news = (
                    News.objects.select_related('category', 'author')
                        .filter(Q(pub_time__range=(start_date, end_date)) & Q(title__icontains=title) & Q(category=category))
                )
        else:
            if category == 0:
                all_news = (
                    News.objects.select_related('category', 'author')
                        .filter(pub_time__range=(start_date, end_date))
                )
            else:
                all_news = (
                    News.objects.select_related('category', 'author')
                        .filter(Q(pub_time__range=(start_date, end_date)) & Q(category=category))
                )
        return all_news

    def get(self,request):
        date_range = request.GET.get('daterange','')
        title = request.GET.get('title','')
        category_id = int(request.GET.get('category',0) or 0)
        all_news = self.query(date_range,title,category_id)

        # 分页
        page = int(request.GET.get('p',1))
        paginator = Paginator(all_news,self.item_limit_per_page)
        page_obj = paginator.page(page)
        context_data = self.get_pagination_data(paginator,page_obj)
        context = {
            'categories': NewsCategory.objects.all(),
            'all_news':page_obj.object_list,
            'page_obj':page_obj,
            'paginator':paginator,
            'daterange':date_range,
            'title':title,
            'category_id':category_id,
            'url_query': '&' + parse.urlencode({
                'daterange':date_range,
                'category':category_id,
                'title':title
            })
        }
        print('打印context:')
        print(context)
        context.update(context_data)
        return render(request, 'cms/news_list.html', context=context)

    def get_pagination_data(self, paginator,page_obj,around_count=2):
        current_page = page_obj.number
        num_pages = paginator.num_pages
        left_has_more = False
        right_has_more = False

        if current_page < around_count + 2:
            left_pages = range(1,current_page)
        else:
            left_has_more = True
            left_pages = range(current_page - around_count, current_page)

        if current_page >= num_pages - around_count - 1:
            right_pages = range(current_page + 1, num_pages + 1)
        else:
            right_has_more = True
            right_pages = range(current_page + 1, current_page + around_count + 1)
        print('左边',left_pages)
        print('右边',right_pages)
        return {
            # 代表的是当前这页左边的页码
            'left_pages':left_pages,
            # 代表的是当前这页右边的页码
            'right_pages':right_pages,
            # 当前页
            'current_page':current_page,
            # 左边冗余
            'left_has_more':left_has_more,
            # 右边冗余
            'right_has_more':right_has_more,
            # 页数
            'num_pages':num_pages
        }


@method_decorator(permission_required(perm='news.add_news',login_url='/'), name='dispatch')
class WriteNewsView(View):

    def get(self,request):
        categories = NewsCategory.objects.all()
        context = {
            'categories':categories
        }
        return render(request,'cms/write_news.html',context=context)

    def post(self,request):
        form = WriteNewsForm(request.POST)

        print('进入写')
        print(request.POST)
        if form.is_valid():
            cleaned_data = form.cleaned_data
            print(cleaned_data)
            title = cleaned_data.get('title')
            desc = cleaned_data.get('desc')
            thumbnail = cleaned_data.get('thumbnail')
            content = cleaned_data.get('content')
            category_id = cleaned_data.get('category')
            category = NewsCategory.objects.get(pk=category_id)
            News.objects.create(
                title=title,
                desc=desc,
                thumbnail=thumbnail,
                content=content,
                category=category,
                author=request.user
            )
            return restful.ok()
        else:
            return restful.params_error(message='数据填写有误')


def news_category(request):
    categories = NewsCategory.objects.all()
    context = {
        'categories':categories
    }
    return render(request,'cms/news_category.html',context=context)


@require_POST
def add_news_category(request):
    name = request.POST.get('name')
    exists = NewsCategory.objects.filter(name=name).exists()
    if not exists:
        NewsCategory.objects.create(name=name)
        return restful.ok()
    else:
        return restful.params_error(message='该分类已经存在')


@require_POST
def edit_news_category(request):
    print('进入编辑函数')
    form = EditNewsCategoryForm(request.POST)
    if form.is_valid():
        print('数据已验证')
        pk = form.cleaned_data.get('pk')
        name = form.cleaned_data.get('name')
        try:
            NewsCategory.objects.filter(pk=pk).update(name=name)
            return restful.ok()
        except Exception as e:
            return restful.params_error(message='该分类不存在！')
    else:
        return restful.params_error(message=form.get_error())


@require_POST
def delete_news_category(request):
    pk = request.POST.get('pk')
    if pk:
        try:
            NewsCategory.objects.filter(pk=pk).delete()
            return restful.ok()
        except:
            return restful.params_error(message='该分类不存在')
    else:
        return restful.params_error(message='内部错误')


@require_POST
def upload_file(request):
    file = request.FILES.get('file')
    name = file.name
    with open(os.path.join(settings.MEDIA_ROOT,name),'wb') as f:
        for chunk in file.chunks():
            f.write(chunk)
    url = request.build_absolute_uri(settings.MEDIA_URL + name)
    return restful.result(data={'url':url})


@require_GET
def qntoken(request):
    q = qiniu.Auth(settings.QINIU_ACCESS_KEY,settings.QINIU_SECRET_KEY)
    token = q.upload_token(settings.QINIU_BUCKET_NAME)
    return restful.result(data={'token':token})


def banners(request):
    return render(request,'cms/banners.html')


# 如果在form中定义id字段，是无法读取的，真是奇怪
def add_banner(request):
    form = AddBannerForm(request.POST)
    print(request.POST)
    if form.is_valid():
        banner_id = form.cleaned_data.get('pk')
        priority = form.cleaned_data.get('priority')
        image_url = form.cleaned_data.get('image_url')
        link_to = form.cleaned_data.get('link_to')
        if banner_id == -1:
            print('进入创建')
            banner = Banner.objects.create(priority=priority,image_url=image_url,link_to=link_to)
            banner_id = banner.pk
        else:
            print('进入更新')
            Banner.objects.filter(id=banner_id).update(priority=priority,image_url=image_url,link_to=link_to)
        return restful.result(data={'banner_id':banner_id})
    else:
        return restful.params_error(message=form.get_errors())


def banner_list(request):
    serializer = BannerSerializer(Banner.objects.all(),many=True)
    return restful.result(data=serializer.data)


@require_POST
def delete_banner(request):
    banner_id = request.POST.get('banner_id')
    Banner.objects.filter(pk=banner_id).delete()
    return restful.ok()


@method_decorator(permission_required(perm='news.change_news',login_url='/'), name='dispatch')
class EditNewsView(View):

    def get(self,request):
        news_id = request.GET.get('news_id')
        news = News.objects.get(pk=news_id)
        context = {
            'news':news,
            'categories':NewsCategory.objects.all()
        }
        return render(request,'cms/write_news.html',context=context)

    def post(self,request):
        form = EditNewsForm(request.POST)

        print('进入写')
        print(request.POST)
        if form.is_valid():
            cleaned_data = form.cleaned_data
            print(cleaned_data)
            title = cleaned_data.get('title')
            desc = cleaned_data.get('desc')
            thumbnail = cleaned_data.get('thumbnail')
            content = cleaned_data.get('content')
            category_id = cleaned_data.get('category')
            pk = cleaned_data.get('pk')
            category = NewsCategory.objects.get(pk=category_id)
            News.objects.filter(pk=pk).update(
                title=title,
                desc=desc,
                thumbnail=thumbnail,
                content=content,
                category=category,
                author=request.user
            )
            return restful.ok()
        else:
            return restful.params_error(message='数据填写有误')


@require_POST
@method_decorator(permission_required(perm='news.delete_news',login_url='/'))
def delete_news(request):
    news_id = request.POST.get('news_id')
    if news_id:
        News.objects.filter(pk=news_id).delete()
        return restful.ok()
    else:
        return restful.params_error(message='查无此新闻')
